package com.app.web.user.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.app.utils.base.j2se.Common;
import com.app.utils.base.j2se.Convert;
import com.app.utils.base.j2se.JsonUtil;
import com.app.utils.base.j2se.MapHandler;
import com.app.utils.redis.KeyParam;
import com.app.utils.redis.Redis;
import com.app.utils.spring.properties.Config;
import com.app.web.user.app.AppInfo;
import com.app.web.user.info.UserInfo;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Description
 * Created by 王伟
 * Date create on 14:26 2019/11/19.
 */
@Service
public class LoginService {
    @Autowired
    private LoginDao loginDao;

    /** 登录令牌过期时间30天 */
    private final int tokenTimeOut = 15*24*60*60;
    /** 用户缓存过期时间3天 */
    private final int loginInfoTimeOut = 30*60*60;
    /** 手机验证码缓存过期时间5分钟 */
    private final int bindMobileCodeTimeOut = 5*60;
    static final int defaultMcode = 1;

    public LoginInfo selectByPrimaryKey(int id){
        return new LoginInfo();
    }

    /**
     * 获取微信accessToken
     */
    public String accessToken(AppInfo appInfo){
        return Redis.str.get("WxAccessToken:"+appInfo.getApp_id());
    }

    /**
     * 刷新微信accessToken
     */
    public void accessTokenRefresh(AppInfo appInfo) throws WxErrorException {
        String accessToken = appInfo.getWxMaService().getAccessToken();
        Redis.str.set("WxAccessToken:"+appInfo.getApp_id(),accessToken,360000);
    }

    /**
     * 微信accessToken剩余时间
     */
    public long accessTokenTime(AppInfo appInfo){
        Long ttl = Redis.key.getExpire("WxAccessToken:"+appInfo.getApp_id());
        return Common.isEmpty(ttl)?0:ttl;
    }

    /**
     * 查询登录信息
     * @param userId 用户ID
     * @return 登录信息
     */
    @SuppressWarnings("rawtypes")
    public LoginInfo info(int userId){
        //缓存中登录信息没有失效 直接返回
        String userKey = KeyParam.userInfoByUid(userId);
        Map loginCache = Redis.hash.hgetall(userKey);
        if(Common.isNotEmpty(loginCache) && Common.isNotEmpty(loginCache.get("id"))){
            return JsonUtil.mapToBean(loginCache,LoginInfo.class);
        }
        //缓存已经失效 查询数据库 将登录信息缓存到redis
        LoginInfo loginInfo = loginDao.infoById(userId);
        if(null != loginInfo){
            Map<String, Object> initCache = (JSONObject)JSON.toJSON(loginInfo);
            Redis.hash.hmset(userKey,MapHandler.obj2StrNotNull(initCache),loginInfoTimeOut);
        }
        return loginInfo;
    }

    /**
     * 功能：根据unid查询登录信息
     * @param unionId 微信unid
     * @return
     */
    public LoginInfo info(String unionId){
        //查询缓存中 unid 和 userId 的映射关系 查询到了 通过用户ID查询登录信息
        String unidKey = KeyParam.uidByUnion(unionId);
        String userId = Redis.str.getAndExpire(unidKey,tokenTimeOut);
        if(Common.isNotEmpty(userId)){
            return info(Convert.objToInt(userId));
        }
        //没有查询到 通过unid查询用户信息 并缓存
        LoginInfo loginInfo = loginDao.infoByUnId(unionId);
        if(Common.isNotEmpty(loginInfo)){
            String userKey = KeyParam.userInfoByUid(loginInfo.getId());

            Redis.str.set(unidKey,loginInfo.getId(),tokenTimeOut);
            Redis.hash.hmset(userKey,MapHandler.obj2StrNotNull(JsonUtil.beanToMap(loginInfo)),loginInfoTimeOut);
        }
        return loginInfo;
    }

    /**
     * 功能：添加登录信息
     * @param loginInfo 登录信息
     * @return
     */
    public void add(LoginInfo loginInfo){
        try {
            //增加登录记录
            if(loginDao.addInfo(loginInfo) <= 0){
                throw new RuntimeException("添加登录信息失败");
            }
        }catch (Exception e){
            //TODO 主键冲突处理为成功
//            if(!Common.mySQLPKConflict(e)){
                throw e;
//            }
        }

    }

    /**
     * 功能:更新登录信息
     * @param loginInfo 登录信息
     * @return
     */
    public void update(LoginInfo loginInfo){
        if(loginDao.updateInfo(loginInfo) <= 0){
            throw new RuntimeException("登录信息更新失败");
        }
        String userKey = KeyParam.userInfoByUid(loginInfo.getId());
        Redis.hash.hmset(userKey,MapHandler.obj2StrNotNull(JsonUtil.beanToMap(loginInfo)),loginInfoTimeOut);
    }

    /**
     * 添加用户黑名单
     * @param userId 用户id
     */
    public int addBlack(int userId){
        loginDao.addBlack(userId);
        return 1;
    }

    /**
     * 添加取消黑名单
     * @param userId 用户id
     */
    public int cancelBlack(int userId){
        loginDao.cancelBlack(userId);
        return 1;
    }

    /**
     * 组装登录用户信息
     * @param loginInfo 登录信息
     * @param userInfo 用户信息
     * @return 登录用户信息
     */
    public Map<String,Object> loginUser(LoginInfo loginInfo, UserInfo userInfo){
        Map<String,Object> loginUser = new HashMap<>();
        loginUser.put("uid", loginInfo.getId());
        loginUser.put("alias", loginInfo.getId());//用户别名，用于绑定消息推送
        loginUser.put("role", userInfo.getRole());
        loginUser.put("mcode", userInfo.getMcode());
        loginUser.put("roleName", userInfo.getRoleName());
        loginUser.put("nickName", loginInfo.getNickName());
        loginUser.put("avatarUrl", loginInfo.getAvatarUrl());
        loginUser.put("gender", loginInfo.getGender());
        loginUser.put("unionId",loginInfo.getUnionId());
        loginUser.put("bindMcode", bindMcode(loginInfo, userInfo));//授权用户的所属mcode，会员自己的mcode，游客就是bindPid对应的mcode。
        loginUser.put("roleImg", userInfo.getRole()==0?"":String.format(Config.pp.getOrDefault("user.roleImg", "https://aloss.taomeimei.net/back/user/role/level-%s.png"),userInfo.getRole()));//授权用户的所属mcode，会员自己的mcode，游客就是bindPid对应的mcode。
        return loginUser;
    }


    /** 授权用户的所属mcode，会员自己的mcode，游客就是bindMcode对应的mcode。 */
    private int bindMcode(LoginInfo loginInfo, UserInfo userInfo){
        if(userInfo.isLeader() || userInfo.isManager()){
            return userInfo.getMcode();
        }
        return Common.isEmpty(loginInfo.getBind_mcode())?defaultMcode:loginInfo.getBind_mcode();
    }
}
